<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务，帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2024 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件，不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types = 1);

namespace app\store\service\order;

use app\common\enum\order\export\ExportStatus as ExportStatusEnum;
use app\common\enum\order\OrderStatus as OrderStatusEnum;
use app\common\enum\order\PayStatus as PayStatusEnum;
use app\common\enum\payment\Method as PaymentMethodEnum;use app\common\library\helper;
use app\common\service\BaseService;use app\store\model\Order as OrderModel;use app\store\model\order\Export as ExportModel;
use cores\exception\BaseException;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use think\facade\Db;

/**
 * 服务层：订单导出Excel
 * Class Export
 * @package app\store\service\order
 */
class Export extends BaseService
{
    // 表格文件标题名称
    private string $title = '订单导出结果';

    /**
     * 执行订单导出excel
     * @param array $param
     * @return bool
     * @throws BaseException
     */
    public function exportOrder(array $param): bool
    {
        // 根据条件查询订单列表
        $orderList = $this->getOrderList($param);

        if ($param['serviceType'] == 'peihu') {
            // 获取导出的记录列名集

            $param['columns'] = ['order_no', 'goods_detail', 'total_price', 'first_pay_price', 'xufei_price', 'create_time', 'user_info', 'mobile', 'real_name', 'bed_no', 'bed_fee', 'pay_status','pay_method', 'pay_time', 'clerk', 'day_price', 'hour_price', 'real_day', 'out_price', 'money', 'extract_shop_name', 'build', 'room', 'floor', 'peihu_date', 'order_status', 'peihu_time', 'buyer_remark', 'merchant_remark'];
        }

        if ($param['serviceType'] == 'park') {
            // 获取导出的记录列名集

            $param['columns'] = ['order_no', 'goods_detail', 'total_price', 'pay_price_unit', 'park_time', 'end_date', 'mobile', 'real_name', 'car_no', 'park_address', 'create_time', 'user_info', 'pay_status', 'pay_time', 'merchant_remark', 'buyer_remark'];
        }
        if ($param['serviceType'] == 'pei') {
            // 获取导出的记录列名集-陪诊

            $param['columns'] = ['order_no', 'goods_detail', 'total_price', 'pay_price_unit', 'create_time', 'user_info', 'mobile', 'real_name', 'park_time', 'doctor', 'room', 'pay_status', 'pay_time',
                'order_status', 'merchant_remark', 'buyer_remark'];
        }
        if ($param['serviceType'] == 'run') {
            // 获取导出的记录列名集-跑腿

            $param['columns'] = ['order_no', 'goods_detail', 'total_price', 'pay_price_unit', 'create_time', 'user_info', 'mobile', 'real_name', 'pay_status', 'pay_time', 'build', 'room', 'floor', 'end_date', 'order_status', 'park_time', 'merchant_remark', 'bed_no', 'yao_name', 'buyer_remark'];
        }
        $columns = $this->getColumns($param['columns']);

        // 格式化生成表格数据
        $excelList = $this->getExcelList($orderList->toArray(), $param['columns']);

        // 输出并写入到excel文件
        $filePath = $this->outputExcel($columns, $excelList);
        // 新增订单导出记录
        $this->record($param, $filePath);
        return true;
    }

    /**
     * 根据条件查询订单列表
     * @param array $param
     * @return mixed
     * @throws BaseException
     */
    private function getOrderList(array $param)
    {
        // 根据条件查询订单列表
        $orderList = (new OrderModel)->getListAll($param);

        if (empty($orderList) || $orderList->isEmpty()) {
            throwError('很抱歉，没有查询到订单数据');
        }
        return $orderList;
    }

    /**
     * 输出并写入到excel文件
     * @param array $columns 列名
     * @param array $excelList 表格内容
     * @return string
     * @throws BaseException
     */
    private function outputExcel(array $columns, array $excelList): string
    {
        // 生成工作表
        $spreadsheet = new Spreadsheet();
        $sheet       = $spreadsheet->getActiveSheet()->setTitle($this->title);
        // 列宽
        $sheet->getDefaultColumnDimension()->setWidth(24);
        // 默认行高
        $sheet->getDefaultRowDimension()->setRowHeight(20);
        // 字体加粗(第一行)
        $sheet->getStyle('1')->getFont()->setBold(true);
        // 写入标题数据
        foreach ($columns as $key => $val) {
            $sheet->setCellValueByColumnAndRow($key + 1, 1, $val);
        }
        // 写入内容数据
        foreach ($excelList as $key => $item) {
            $row = $key + 2;
            foreach (array_values($item) as $k => $val) {
                $sheet->setCellValueByColumnAndRow($k + 1, $row, $val);
            }
        }
        // 生成文件路径
        $fileName = 'order-' . time() . '.xlsx';
        // 获取导出的文件夹路径
        $filePath = $this->getExportPath();
        // 保存到文件
        try {
            $writer = new Xlsx($spreadsheet);
            $writer->save(public_path() . $filePath . $fileName);
        } catch (\PhpOffice\PhpSpreadsheet\Writer\Exception $e) {
            throwError($e->getMessage());
        }
        return $filePath . $fileName;
    }

    /**
     * 获取导出的文件夹路径
     * @return string
     */
    private function getExportPath(): string
    {
        $filePath = 'downloads/' . $this->getStoreId() . '/';
        ! is_dir($filePath) && mkdir($filePath, 0755, true);
        return $filePath;
    }

    /**
     * 写入订单导出记录
     * @param array $param
     * @param string $filePath
     * @return void
     */
    private function record(array $param, string $filePath): void
    {
        // 生成记录数据
        $data = [
            'file_path' => $filePath,
            'status'    => ExportStatusEnum::COMPLETED,
            'store_id'  => $this->getStoreId(),
        ];
        // 起止时间
        if (! empty($param['betweenTime'])) {
            $times              = between_time($param['betweenTime']);
            $data['start_time'] = $times['start_time'];
            $data['end_time']   = $times['end_time'];
        }
        // 新增记录
        $model = new ExportModel;
        $model->add($data);
    }

    /**
     * 获取导出的记录列名集
     * @param array $onlyFields
     * @return array
     */
    private function getColumns(array $onlyFields): array
    {
        return array_values(helper::pick($this->dictionary(), $onlyFields));
    }

    /**
     * 订单记录字典
     * @return string[]
     */
    private function dictionary(): array
    {
        return [
            'order_id'          => '订单ID',
            'order_no'          => '订单号',
            'goods_detail'      => '服务信息',
            'total_price'       => '订单总额',
            'first_pay_price'   => '首次缴费',
            'xufei_price'       => '续费',
            'pay_price_unit'    => '缴费金额',
            'bed_fee'           => '陪床费',
            'pay_price'         => '订单实付款',
            'create_time'       => '下单时间',
            'end_date'          => '结束时间',
            'user_info'         => '用户信息',
            'real_name'         => '被服务人姓名',
            'mobile'            => '联系电话',
            'build'             => '楼栋',
            'floor'             => '楼层',
            'room'              => '科室',
            'bed_no'            => '床位',
            'build'             => '楼栋',
            'doctor'            => '医生',
            'yao_name'          => '药品名称',
            'park_address'      => '停车地址',
            'extract_shop_name' => '医院',
            'pay_status'        => '付款状态',
            'pay_method'        => '付款方式',
            'pay_time'          => '付款时间',
            'peihu_date'        => '陪护日期',
            'peihu_time'        => '陪护时间',
            'clerk'             => '陪护师',
            'day_price'         => '工资（天）',
            'hour_price'        => '半小时薪',
            'real_day'          => '实际陪护天数',
            'out_price'         => '额外奖励金额',
            'money'             => '陪护师工资',
            'park_time'         => '服务时间',
            'order_status'      => '订单状态',
            'out_trade_no'      => '第三方支付订单号',
            'trade_no'          => '支付流水号',
            'buyer_remark'      => '用户备注',
            'merchant_remark'   => '后台备注',
        ];
    }

    /**
     * 格式化生成表格数据
     * @param array $orderList
     * @param array $onlyFields
     * @return array
     */
    private function getExcelList(array $orderList, array $onlyFields): array
    {

        // 获取订单表格数据
        $excelList = $this->getOrderDataForExcel($orderList);
        // 仅输出用户设置的字段
        $data = [];
        foreach ($excelList as $item) {
            $data[] = helper::pick($item, $onlyFields);
        }
        return $data;
    }

    /**
     * 获取订单列表数据(用于生成Excel)
     * @param $orderList
     * @return array
     */
    private function getOrderDataForExcel($orderList): array
    {

        // 表格内容
        $dataArray = [];
        foreach ($orderList as $order) {
            if ($order['order_type'] == 10) {
                //支付记录
                $dd = Db::name('order_pay_log')->where('order_id', $order['order_id'])->field('pay_price as pay_price_unit,create_time as create_time_unit,order_id')->select()->toArray();

             
            
                if (count($dd) == 1) {

                    $order['pay_price']       = $dd[0]['pay_price_unit'];
                    $order['first_pay_price'] = Date('Y-m-d H:i:s') . '/' . $dd[0]['pay_price_unit'];
                    $order['xufei_price']     = '';
                    $order['create_time']     =  Date('Y-m-d H:i:s', $dd[0]['create_time_unit']);
                }
                if (count($dd) > 1) {
                    $order['pay_price']       = $dd[0]['pay_price_unit'];
                    $order['create_time']     =  Date('Y-m-d H:i:s', $dd[0]['create_time_unit']);
                    $order['first_pay_price'] = Date('Y-m-d H:i:s', $dd[0]['create_time_unit']) . '/' . $dd[0]['pay_price_unit'];

                    unset($dd[0]);
                    $xufei_price = '';
                    foreach ($dd as $k => $v) {
                        $date = Date('Y-m-d H:i:s', $v['create_time_unit']) . '/' . $v['pay_price_unit'];
                        $xufei_price .= "{$date}\n";

                    }

                    $order['xufei_price'] = $xufei_price;

                }
            }

            $dataArray[] = [
                'order_id'          => $this->filterValue($order['order_id']),
                'order_no'          => $this->filterValue($order['order_no']),
                'goods_detail'      => $this->filterGoodsInfo($order),
                'total_price'       => (int) $order['total_price'],
                'pay_price_unit'    => (int) $order['pay_price'],
                'first_pay_price'   => isset($order['first_pay_price']) ? $order['first_pay_price'] : '',
                'xufei_price'       => isset($order['xufei_price']) ? $order['xufei_price'] : '',
                'pay_price_unit'    => (int) $order['pay_price'],
                'bed_fee'           => (int) $order['bed_fee'],
                'pay_price'         => (int) $order['total_price'],

                'create_time'       => $this->filterValue($order['create_time']),
                'user_info'         => $this->filterValue($order['user']['nick_name']),
                'real_name'         => $this->filterValue($order['real_name']),
                'mobile'            => $this->filterValue($order['mobile']),
                'build'             => $order['build'] ? $this->filterValue($order['build']['name']) : '',
                'floor'             => $this->filterValue($order['floor']),
                'room'              => $this->filterValue($order['room']),
                'bed_no'            => $this->filterValue($order['bed_no']),
                'doctor'            => $this->filterValue($order['doctor']),
                'yao_name'          => $this->filterValue($order['yao_name']),
                'park_address'      => $this->filterValue($order['park_address']),
                'extract_shop_name' => ! empty($order['extract_shop']) ? $order['extract_shop']['shop_name'] : '',
                'pay_status'        => PayStatusEnum::data()[$order['pay_status']]['name'],
                              'pay_method'        => $this->filterPayMethod($order['pay_method']),
                'pay_time'          => $order['pay_time'],
                'peihu_date'        => $order['start_date'] . '-' . $order['end_date'],
                'end_date'          => $order['end_date'],
                'peihu_time'        => $order['peihu_time'],

                'order_status'      => OrderStatusEnum::data()[$order['order_status']]['name'],
                'out_trade_no'      => ! empty($order['trade']) ? $this->filterValue($order['trade']['out_trade_no']) : '',
                'trade_no'          => ! empty($order['trade']) ? $this->filterValue($order['trade']['trade_no']) : '',
                'buyer_remark'      => $order['buyer_remark'] ? $this->filterValue($order['buyer_remark']) : '',
                'merchant_remark'   => $order['merchant_remark'],
            ];

        }
        return $dataArray;
    }

    /**
     * 格式化支付方式
     * @param string $payMethod
     * @return string
     */
    private function filterPayMethod(string $payMethod): string
    {
        $enum = PaymentMethodEnum::data();
        return isset($enum[$payMethod]) ? $enum[$payMethod]['name'] : '';
    }

    /**
     * 格式化商品信息
     * @param $order
     * @return string
     */
    private function filterGoodsInfo($order): string
    {
        $content = '';
        foreach ($order['goods'] as $key => $goods) {
            $content .= "{$goods['goods_name']}\n";
            $content .= " 服务价格：{$goods['goods_price']}\n";

        }
        return $content;
    }

    /**
     * 表格值过滤
     * @param $value
     * @return string
     */
    private function filterValue($value): string
    {
        return "\t{$value}\t";
    }
}
